package cn.iocoder.yudao.module.infra.tts.impl.minimax;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.infra.okhttp.OkHttpUtils;
import cn.iocoder.yudao.module.infra.tts.TTSConfig;
import cn.iocoder.yudao.module.infra.tts.impl.SimpleTTSApi;
import cn.iocoder.yudao.module.infra.tts.impl.minimax.model.MinimaxBaseRes;
import cn.iocoder.yudao.module.infra.tts.impl.minimax.model.MinimaxTTSReq;
import cn.iocoder.yudao.module.infra.tts.impl.minimax.model.MinimaxTTSRes;
import com.fasterxml.jackson.databind.JsonNode;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service("tts-minimax")
public class MinimaxTTSApi extends SimpleTTSApi {
    private static String targetModel = "speech-02-turbo";
    private static final String prefix = "minimax_";
    private static final String URL_UPLOAD_FILE = "https://api.minimax.chat/v1/files/upload?GroupId=";
    private static final String URL_CREATE_VOICE = "https://api.minimax.chat/v1/voice_clone?GroupId=";
    private static final String URL_TTS = "https://api.minimax.chat/v1/t2a_v2?GroupId=";

    private TTSConfig.Config minimaxConfig;

    @Resource
    private TTSConfig ttsConfig;

    @PostConstruct
    public void init() {
        minimaxConfig = ttsConfig.getService("minimax");
    }

    @Override
    public String createCloneVoice(String fileUrl) {
        try {
            final File tempFile = new File("/data/datas/temp/" + IdUtil.objectId() + ".mp3");
            tempFile.getParentFile().mkdirs();
            log.info("下载文件开始, fileUrl = {}, tempFile = {}", fileUrl, tempFile.getAbsolutePath());

            HttpUtil.downloadFile(fileUrl, tempFile);
            log.info("下载文件完成, fileUrl = {}, tempFile = {}", fileUrl, tempFile.getAbsolutePath());

            final String appId = minimaxConfig.getAppid();
            final String apiKey = minimaxConfig.getApiKey();
            final String fileId = uploadFile(tempFile, "voice_clone", appId, apiKey);

            final String voiceId = prefix + IdUtil.objectId();
            createCloneVoice(fileId, voiceId);
            return voiceId;
        } catch (Exception e) {
            if (e instanceof RuntimeException) {
                throw (RuntimeException) e;
            } else {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public byte[] convertTextToSpeech(Integer audioToneId, String cloneVoiceId, String voice,
                                      String voice_path, String voice_hash,
                                      String voice_suffix, String response_format, String input) {
        final long startTime = System.currentTimeMillis();

        final String appId = minimaxConfig.getAppid();
        final String apiKey = minimaxConfig.getApiKey();

        final MinimaxTTSReq req = MinimaxTTSReq.builder()
                .model(targetModel)
                .text(input)
                .stream(false)
                .output_format("hex")
                .voice_setting(MinimaxTTSReq.VoiceSetting.builder().voice_id(cloneVoiceId).build())
                .audio_setting(MinimaxTTSReq.AudioSetting.builder().format(response_format).build())
                .build();
        final String body = JsonUtils.toJsonString(req);
        log.info("文本转语音开始, cloneVoiceId = {}, input = {}, body = {}", cloneVoiceId, input, body);

        final Request request = new Request.Builder()
                .url(URL_TTS + appId)
                .header("Content-Type", "application/json")
                .header("Authorization", "Bearer " + apiKey)
                .post(RequestBody.create(MediaType.parse("application/json"), body))
                .build();
        try (Response response = OkHttpUtils.getTtsClient().newCall(request).execute()) {
            byte[] audioData = null;
            Long errorCode = null;
            String errorMsg = null;
            final String responseBody = response.body() != null ? response.body().string() : null;

            if (response.isSuccessful() && response.body() != null) {
                final MinimaxTTSRes minimaxTTSRes = JsonUtils.parseObject(responseBody, MinimaxTTSRes.class);
                if (minimaxTTSRes.getData() != null && StrUtil.isNotEmpty(minimaxTTSRes.getData().getAudio())) {
                    final String audioHex = minimaxTTSRes.getData().getAudio();
                    audioData = HexUtil.decodeHex(audioHex);
                }
                if (minimaxTTSRes.getBase_resp() != null) {
                    errorCode = minimaxTTSRes.getBase_resp().getStatus_code();
                    errorMsg = minimaxTTSRes.getBase_resp().getStatus_msg();
                }
            }

            if (audioData != null && audioData.length > 0) {
                final long duration = System.currentTimeMillis() - startTime;
                log.info("文本转语音完成, cloneVoiceId = {}, audioData.len = {}, input = {}, duration = {}",
                        cloneVoiceId, audioData.length, input, duration);
                return audioData;
            } else {
                log.error("文本转语音失败, code = {}, errorCode = {}, errorMsg = {}, body = {}",
                        response.code(), errorCode, errorMsg, responseBody);
                throw new RuntimeException("文本转语音失败: " + errorMsg);
            }
        } catch (Exception e) {
            final long duration = System.currentTimeMillis() - startTime;
            log.error(StrUtil.format("文本转语音异常, cloneVoiceId = {}, input = {}, duration = {}",
                    cloneVoiceId, input, duration), e);
            throw new RuntimeException("文本转语音请求异常", e);
        }
    }

    private void createCloneVoice(String fileId, String voiceId) throws IOException {
        log.info("创建音色开始, fileId = {}, voiceId = {}", fileId, voiceId);

        final Map<String, Object> payload = new HashMap<>();
        payload.put("file_id", Long.parseLong(fileId));
        payload.put("voice_id", voiceId);
        payload.put("need_noise_reduction", false);

        // 构建请求
        final String appId = minimaxConfig.getAppid();
        final String apiKey = minimaxConfig.getApiKey();
        final Request request = new Request.Builder()
                .url(URL_CREATE_VOICE + appId)
                .header("Authorization", "Bearer " + apiKey)
                .header("Content-Type", "application/json")
                .post(RequestBody.create(JsonUtils.toJsonString(payload), MediaType.parse("application/json")))
                .build();

        // 发送请求并返回响应
        try (Response response = OkHttpUtils.getDefaultHttpClient().newCall(request).execute()) {
            final String traceId = response.header("Trace-ID");
            final String responseBody = response.body() != null ? response.body().string() : null;
            if (!response.isSuccessful()) {
                log.error("创建音色失败, fileId = {}, voiceId = {}, traceId = {}, response = {}",
                        fileId, voiceId, traceId, responseBody);
                throw new RuntimeException("创建音色失败: " + responseBody);
            }

            final MinimaxBaseRes baseRes = JsonUtils.parseObject(responseBody, MinimaxBaseRes.class);
            if (baseRes == null
                    || baseRes.getBase_resp() == null
                    || baseRes.getBase_resp().getStatus_code() == null
                    || baseRes.getBase_resp().getStatus_code() != 0) {
                log.warn("创建音色失败, code = {}, response = {}", response.code(), responseBody);
                throw new IOException("创建音色失败: " + responseBody);
            }

            log.info("创建音色成功, fileId = {}, voiceId = {}, traceId = {}, response = {}",
                    fileId, voiceId, traceId, responseBody);
        }
    }

    private static String uploadFile(File file, String purpose, String appId, String apiKey) throws IOException {
        log.info("上传文件开始, file = {}, purpose = {}", file, purpose);

        // 构建 multipart 请求体
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("purpose", purpose)
                .addFormDataPart(
                        "file",
                        file.getName(),
                        RequestBody.create(file, MediaType.parse("application/octet-stream"))
                )
                .build();

        // 构建请求
        Request request = new Request.Builder()
                .url(URL_UPLOAD_FILE + appId)
                .header("Authorization", "Bearer " + apiKey)
                .post(requestBody)
                .build();

        // 发送请求并解析响应
        try (Response response = OkHttpUtils.getDefaultHttpClient().newCall(request).execute()) {
            final String responseBody = response.body() != null ? response.body().string() : null;
            if (!response.isSuccessful()) {
                log.warn("上传文件失败, code = {}, response = {}", response.code(), responseBody);
                throw new IOException("上传失败: " + responseBody);
            }

            final MinimaxBaseRes baseRes = JsonUtils.parseObject(responseBody, MinimaxBaseRes.class);
            if (baseRes == null
                    || baseRes.getBase_resp() == null
                    || baseRes.getBase_resp().getStatus_code() == null
                    || baseRes.getBase_resp().getStatus_code() != 0) {
                log.warn("上传文件失败, code = {}, response = {}", response.code(), responseBody);
                throw new IOException("上传失败: " + responseBody);
            }

            final JsonNode root = JsonUtils.parseTree(responseBody);
            final String file_id = root.get("file").get("file_id").asText();
            log.info("上传文件成功, file_id = {}, response = {}", file_id, responseBody);
            return file_id;
        }
    }

    public static void main(String[] args) throws Exception {
        final String appId = "";
        final String apiKey = "";
        String file_id = uploadFile(new File("E:/ai/680f30e60634c9ed0dbdc9c5.mp3"), "voice_clone", appId, apiKey);
        System.out.println(file_id);
    }

}
